﻿using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;

using Dxr.Police.Models;
using Zongsoft.Security.Membership;

namespace Dxr.Police.Web.Http.Security
{
    public class AuthenticationFilter : IAuthenticationFilter
    {
        #region 常量定义
        private const string HTTP_AUTHORIZATION_SCHEME = "Credential";
        #endregion

        #region 属性
        [Zongsoft.Services.ServiceDependency]
        public Services.UserInfoService UserInfoService
        { get; set; }

        public bool AllowMultiple
        {
            get
            {
                return true;
            }
        }
        #endregion

        #region 方法
        public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
            var attribute = AuthenticationUtility.GetAuthorizationAttribute(context.ActionContext.ActionDescriptor);

            if (attribute == null || attribute.Mode == AuthorizationMode.Anonymous)
                return;

            string credentialId = null;

            credentialId = AuthenticationUtility.GetCredentialId();

            if (string.IsNullOrEmpty(credentialId) && context.Request.Headers.Authorization != null && string.Equals(context.Request.Headers.Authorization.Scheme, HTTP_AUTHORIZATION_SCHEME, StringComparison.OrdinalIgnoreCase))
                credentialId = context.Request.Headers.Authorization.Parameter.Trim();

            if (string.IsNullOrWhiteSpace(credentialId))
                context.Principal = null;
            else
            {
                var userInfo = (UserInfo)UserInfoService.Get(credentialId);
                //var userInfo = new UserInfo() { Id="1",Name="123"};

                var principal = new Principal(new Identity(credentialId, userInfo, "External"));

                context.Principal = principal;
            }
        }

        public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            var principal = context.ActionContext.RequestContext.Principal;
            var attribute = AuthenticationUtility.GetAuthorizationAttribute(context.ActionContext.ActionDescriptor);

            if (attribute == null || attribute.Mode == AuthorizationMode.Anonymous)
                return;

            if (AuthenticationUtility.IsAuthenticated(principal))
            {
                var role = ((Identity)principal.Identity).UserInfo.Role;

                switch (attribute.Mode)
                {
                    case AuthorizationMode.Identity:
                        if (attribute.Roles != null && attribute.Roles.Length > 0)
                        {
                            if (!attribute.Roles.Any(p => string.Equals(p, role.ToString(), StringComparison.OrdinalIgnoreCase)))
                            {
                                var challenge = new System.Net.Http.Headers.AuthenticationHeaderValue(HTTP_AUTHORIZATION_SCHEME);
                                context.Result = new System.Web.Http.Results.UnauthorizedResult(new[] { challenge }, context.Request);
                                return;
                            }
                        }
                        break;
                    case AuthorizationMode.Requires:
                        throw new NotImplementedException();
                }
            }
            else
            {
                var challenge = new System.Net.Http.Headers.AuthenticationHeaderValue(HTTP_AUTHORIZATION_SCHEME);
                context.Result = new System.Web.Http.Results.UnauthorizedResult(new[] { challenge }, context.Request);
            }
        }
        #endregion
    }
}
